package edu.mapi.ir.viewer;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;

public class BeaconVisibility implements IMapLayer {

	private BufferedImage img;
	private double lastZoom = 0;
	public static double MAX_RADIUS = 15;
	private Maze maze;
	private Beacon beacon;
	private Area visibleArea = null;
	
	public BeaconVisibility(Maze maze, Beacon beacon) {
		this.maze = maze;
		this.beacon = beacon;
		MAX_RADIUS = maze.getWidth();
		computeVisibleArea(MAX_RADIUS);
		
	}
	
	private void computeVisibleArea(double maxRadius) {
		visibleArea = new Area(new Ellipse2D.Double(beacon.getPosition().getX() - maxRadius/2,
				beacon.getPosition().getY() - maxRadius/2, maxRadius, maxRadius));
		
		for (Wall w : maze.getWalls()) {
			if (w.getHeight() < beacon.getHeight())
				continue;
			visibleArea.subtract(new Area(w.getShape()));
			subtractObstacle(w);
		}
		
		//System.out.println(visibleArea.getBounds2D());
	}
	
	private void subtractObstacle(Wall w) {
		
		double cx = beacon.getPosition().getX();
		double cy = beacon.getPosition().getY();
		
		Area a = new Area();
		
		Point2D prevPoint = w.getCorners().lastElement();
		
		for (Point2D p : w.getCorners()) {
			
			GeneralPath gp = new GeneralPath();
			gp.moveTo(p.getX(), p.getY());
			//System.out.print("["+p.getX()+","+p.getY()+"] ");
			double ang = Math.atan2(p.getY()-cy, p.getX()-cx);
			double px = p.getX() + MAX_RADIUS * Math.cos(ang);
			double py = p.getY() + MAX_RADIUS * Math.sin(ang);
			gp.lineTo(px, py);
			//System.out.print("["+px+","+py+"] ");
			ang = Math.atan2(prevPoint.getY()-cy, prevPoint.getX()-cx);
			px = prevPoint.getX() + MAX_RADIUS * Math.cos(ang);
			py = prevPoint.getY() + MAX_RADIUS * Math.sin(ang);			
			gp.lineTo(px, py);
			//System.out.print("["+px+","+py+"] ");
			gp.lineTo(prevPoint.getX(), prevPoint.getY());
			//System.out.println("["+prevPoint.getX()+","+prevPoint.getY()+"]");
			gp.closePath();
			
			a.add(new Area(gp));
			prevPoint = p;
		}
		
		visibleArea.subtract(a);
	}
	
	
	public BufferedImage getLayerImage(double zoom) {
		if (img == null || zoom != lastZoom) {
			img = new BufferedImage((int)(maze.getWidth()*zoom), (int)(maze.getHeight()*zoom), BufferedImage.TYPE_INT_ARGB);
			Graphics2D g = (Graphics2D) img.getGraphics();	
			g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			g.setColor(new Color(255,255,255,100));
			g.scale(zoom, -zoom);
			g.translate(0, -maze.getHeight());
			g.setPaint(new RadialGradientPaint(beacon.getPosition(), (float)MAX_RADIUS, new float[]{0.3f, 0.5f}, 
					new Color[] {new Color(255,200,0,40), new Color(255,200,0,0)}));
			g.fill(visibleArea);
			lastZoom = zoom;
		}
		return img;
	}


	public boolean hasLayerChanged() {		
		return false;
	}

}
